// 设计模式-->子烁爱学习

01 单例模式

实例化时机：
	饿汉式
	懒汉式
		双重检查锁

/*
  概念：
  确保一个类只有一个实例，而且自行实例化并向整个系统提供这个实例。

  确保一个类只有一个实例，那么就要求构造方法一定不能是public公开的，即不能被外界进行实例化，那它的构造方法只能是private。
  这个实例属于当前类，即这个实例是当前类的类成员变量，静态变量用static修饰
  通过一个类成员方法向外界提供这个实例

  单例模式的主要作用是确保一个类只有一个实例存在，比如说序列号生成器、web页面的计数器等等都可以使用单例模式
  同时，如果创建某个对象需要消耗较多资源的话，比如访问IO、或者数据库资源的时候，我们也可以使用单例模式来较少资源的消耗

  singleton应该加volatile [ˈvɒlətaɪl]关键字，singleton = new Singleton() 可以拆解为3步：
  1. 分配内存，
  2. 初始化对象，
  3. 指向刚分配的地址，若发生重排序，
  假设A线程执行了1和3，还没有执行2。B线程来判断singleton是否为null，判断结果singleton不是null，B线程就会直接返回还没有初始化的instance了。volatile可以避免重排序

  单例模式的实例是全局唯一的，但是在以下两种情况下，也会出现多个实例
  1. 分布式系统中，会有多个JVM虚拟机，各个虚拟机都有一个实例
  2. 一个JVM虚拟机中，使用了多个类加载器同时加载这个类，也会产生多个实例

  单例模式一个很严重的问题，就是说如果它有状态的话，比如它有一个字段(value)等于10，那我在某个地方用的时候，先把它修改成20，其他地方调用这个实例，也可以随意修改，比如修改为30。
  所以说单例模式的最佳实践就是无状态的，一般以工具类的形式提供。


*/
public class SingletonPattern {
	public static void main(String[] args) {

	}
}

// 以下是饿汉式
class Singleton {
	private static Singleton singleton = new Singleton();
	private Singleton(){}

	public static Singleton getInstance() {
		return singleton;
	}
}

// 以下是懒汉式
class Singleton {
	private volatile static Singleton singleton;
	private Singleton(){} // 构造方法必须私有化

	public static Singleton getInstance() {
		if (singleton == null) {
			synchronized(Singleton.class) {
				if (singleton == null) {
					Singleton = new Singleton();
				}
			}
		}
		return singleton;
	}
}
===================================================
02 简单工厂模式

/*
  概念：
  又称为静态工厂方法模式，它属于类创建型模式。在简单工厂模式中，可以根据参数的不同返回不同类的实例。
  简单工厂模式专门定义一个类来负责创建其他类的实例，被创建的实例通常都具有共同的父类。

  JDK的DataFormat使用到了简单工厂模式

  简单工厂模式的优点：实现对象的创建和使用的分离，创建完全交给专门的工厂类负责，客户端程序员不关心怎么创建，只关心怎么使用。
  缺点：简单工厂类不够灵活，如果我们新增一个产品就要修改工厂类，修改它的判断逻辑，如果产品很多的话，逻辑就会非常复杂。

*/
public class SimpleFactory{
	public static Product createProduct(String type) {
		if (type.equals("A")) {
			return new ProductA();
		} else {
			return new ProcutB();
		}
	}

	public static void main(String[] args) {
		Product product = SimpleFactory.createProduct("A");
		product.print();

	}
}

abstract class Product{
	public abstract void print();
}

class ProductA extends Product{
	@Override
	public void print() {
		System.out.println("产品A");
	}
}

class ProductB extends Product{
	@Override
	public void print() {
		System.out.println("产品B");
	}
}
===================================================
03 工厂模式

/**
 简单工厂模式违反了开闭原则

定义一个用于创建对象的接口，让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。

 在工厂模式中呢，之前的核心工厂变成了一个抽象接口，它负责给出工厂应该实现的方法，然后呢它不再负责所有产品的创建，而是将具体产品的创建工作交给子类去做
 这样呢，就诞生了具体的子工厂。子工厂，即子类负责生成具体的产品对象。这样做可以将产品类的实例化操作延迟到工厂子类中完成，即通过子类来确定究竟应该实例化
 哪一个具体实例类。

 所以有一个很重要的问题我们应该意识到，就是现在在工厂模式中，如果你要新增一个产品，你不需要修改原有的工厂类逻辑，但是你需要新增一个工厂。引出的问题，为啥不直接修改工厂类？
 原因是在面对对象程序设计中，一个很重要的原则是开闭原则--> 程序对于扩展是开放的，对于修改是封闭的。

 Collection集合类,具体细节见onenote的设计模式章节

 */

public class FactoryPattern{
	public static void main(String[] args) {
		Factory factory = new HuaWeiFactory();
		Phone phone = factory.createProduct();
		phone.print();
	}
}

interface Phone{
	void print();
}

class iPhone implements Phone{
	@Override
	public void print() {
		System.out.println("iPhone");
	}
}
class HuaWeiPhone implements Phone{
	@Override
	public void print() {
		System.out.println("HuaWeiPhone");
	}
}

interface Factory{
	Phone createPhone();
}

class IPhoneFactory implements Factory{
	@Override
	public Phone createPhone() {
		return new iPhone();
	}
}

class HuaWeiFactory implements Factory{
	@Override
	public Phone createPhone() {
		return new HuaWeiPhone();
	}
}

===================================================
04 抽象工厂模式
/**
 * 类图见onenote
 * 抽象工厂模式可以使得具体工厂创建多个"大类"(产品体系)对象，但是还是需要修改抽象工厂和具体工厂的代码，违反了开闭原则
 */

// 抽象工厂
interface AbstractFactory{
	Phone createPhone(String param);
	Mask createMask(String param);
}

// 具体工厂
class SuperFactory implements AbstractFactory {
	@Override
	public createPhone(String param) {
		return new iPhone();
	}
	@Override
	public Mask createMask(String param) {
		return new N95();
	}
}

// 产品大类--手机
interface Phone{}
class iPhone implements Phone{}

// 产品大类--口罩
interface Mask{}
class N95 implements Mask{}
===================================================
05 装饰器模式
/**
 * 详见onenote，图解。
 * 对于第一种继承模式来说，这种方法使静态的，一定是要写一个新的子类，对类层级进行扩展；
 * 第二种方法呢，它是动态的，我们拿到一个对象就可以对其进行扩展，不需要修改原有类逻辑
 * 
 * 概念：
 * 动态地给一个对象添加一些额外的功能。就增加功能来说，装饰模式比生成子类更加灵活
 * 
 * Java的IO流也大量的使用了装饰器模式
 */

public class RobotDecoratorPattern {
	public static void main(String[] args) {
		new RobotDecorator(new FirstRobot).doMoreThing();
	}
}

interface Robot { // 需要被装饰的对象
	void doSomething();
}

class FirstRobot implements Robot{
	@Override
	public void doSomething(){
		System.out.println("对话");
		System.out.println("唱歌");
	}
}

class RobotDecorator implements Robot {
	private Robot robot;
	public RobotDecorator(Robot robot){
		this.robot = robot;
	}

	@Override
	public void doSomething(){
		robot.doSomething();
	}

	public void doMoreThing(){
		robot.doSomething();
		System.out.println("跳舞、拖地");
	}
}
===================================================
06 适配器模式
/**
 * 将一个类的接口变换成客户端所期待的另一种接口，从而使原本因接口不匹配而无法在一起工作的两个类能在一起工作。
 * 
 * 举个例子：新闻联播中的手语老师就是适配器模式
 * 
 * 适配器模式和装饰者模式的区别：
 * 	最主要的区别就是它们的目的不一样，适配器模式是做什么的呢，原有的接口挺好用的，但是客户端不兼容，适配器只是提供一个转换的作用，相当于客户端直接访问原有接口
 * 之间的桥梁，它不会改变原先的接口，但是装饰器模式恰恰相反，它就是为了对原有接口进行功能扩展，所以说需要修改原来的接口。
 */
public class AdapterPattern {
	public static void main(String[] args) {
		new Adapter(new Speaker()).translate();
	}
}

class Speaker{
	public String speak(){
		return "china No.1";
	}
}

// 适配器接口
interface Translator{
	public Stirng translate();
}

class Adapter implements Translator {
	private Speaker speaker;
	public Adapter(Speaker speaker) {
		this.speaker = speaker;
	}
	@Override
	public String translate(){
		String result = speaker.speak();
		// ...理解、手语话
		return result;
	}
}
===================================================
07 观察者模式--发布订阅模式
/**
 * 概念：定义对象间的一种一对多依赖关系，使得每当一个对象状态发生改变时，其相关依赖对象皆得到通知并被自动更新
*/

public class ObserverPattern {
	public static void main(String[] args) {
		Debit zhangSan = new Zhangsan();
		zhangSan.borrow(new Wangwu());
		zhangSan.borrow(new Zhaosi());
		// state改变
		zhangSan.notifyCredits();
	}
}

interface Debit{
	void borrow(Create credit);
	void notifyCredits();
}

class Zhangsan implements Debit{
	private List<Credit> allCredits = new ArrayList<>();
	private Integer state = 0; // 1表示有钱
	@Override
	public void borrow(Credit credit) {
		allCredits.add(credit);
	}

	@Override
	public void notifyCredits(){
		allCredits.forEach(credit -> credit.takeMoney());
	}
}

interface Credit{
	void takeMoney();
}

class Wangwu implements Credit{
	@Override
	public void takeMoney() {
		System.out.println("王五要钱");
	}
}

class Zhaosi implements Credit{
	@Override
	public void takeMoney() {
		System.out.println("赵四要钱");
	}
}
===================================================
08 外观模式
/**
 * 概念：要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。外观模式提供一个高层次的接口，使得子系统更易使用
 * 
 * 外观模式的最大缺点就是不符合开闭原则，如果子系统扩展的话，必须要修改外观模式的类，即必须要修改代码，才能适应子系统的变更
 * 
*/

public class FacadePattern{
	new Facade().prove();
}

class SubFlow1{
	boolean isTrue() {
		return true;
	}
}

class SubFlow2{
	boolean isOk() {
		return true;
	}
}

class SubFlow3{
	boolean isGoodMan() {
		return true;
	}
}

class Facade{
	SubFlow1 s1 = new SubFlow1();
	SubFlow1 s2 = new SubFlow2();
	SubFlow1 s3 = new SubFlow3();

	boolean prove() {
		return s1.isTrue()&&s2.isOk()&&s3.isGoodMan();
	}
}
===================================================
09 状态模式
/**
 * 概念：允许一个对象在其内部状态改变时改变它的行为，对象看起来似乎修改了它的类。
 * 其别名为状态对象(Objects for States)，状态模式是一种对象行为型模式。
 * 
 * 状态模式的主要优点在于封装了转换规则，并枚举了可能的状态，它将所有与某个对状态有关的行为，放到了状态类中，并且可以方便地增加新的状态。
 * 还可以让多个环境对象共享一个状态对象，从而减少系统中对象的个数
 * 
*/
public class StatePattern {
	public static void main(String[] args) {
		Context ZhangSan = new Context();
		ZhangSan.changeState(new Happy());
		ZhangSan.doSomething();

		ZhangSan.changeState(new Sad());
		ZhangSan.doSomething();
	}
}

abstract class State{
	abstract void doWork();
}

class Happy extends State{
	@Override
	void doWork() {
		System.out.println("积极主动！");
	}
}

class Angry extends State{
	@Override
	void doWork() {
		System.out.println("无精打采！");
	}
}

class Sad extends State{
	@Override
	void doWork() {
		System.out.println("啥也不干！");
	}
}

class Context{
	private State state;
	public void changeState(State state) {
		this.state = state;
	}
	public void doSomething(){
		state.doWork();
	}
}
===================================================
10 策略模式
/**
 * 定义一组算法，将每个算法都封装起来，并且使它们之间可以互换。策略模式让算法独立于使用它的客户而变化，也成为政策模式。
 *
*/

public class StrategyPattern{
	public static void main(String[] args) {
		TreadPoolExecutor executor = new TreadPoolExecutor("拒绝策略");
	}
}
===================================================
11 代理模式
/**
 * 为其他对象提供一种代理以控制对这个对象的访问
 * 
*/
public class ProxyPattern{
	public static void main(String[] args) throws ClassNotFoundException{
		new RealSubjectProxy().doWork();
	}
}

interface Subject{
	void doWork();
}

class RealSubject implements Subject{
	@Override
	public void doWork(){
		System.out.println("Hello World!");
	}
}

class RealSubjectProxy implements Subject{
	private RealSubject Subject;

	// public RealSubjectProxy(RealSubjecte subject) {
	// 	this.subject = subject;
	// }

	// 通过类加载器的形式可以不用在参数列表中传入被代理类的对象
	public RealSubjectProxy() {
		try{
			this.subject = (RealSubject)this.getClass().getClassLoader().loadClass("xxx.xxx.RealSubject").newInstance();
		}
	}

	public void connect(){
		System.out.println("建立连接");
	}

	public void log() {
		System.out.println("日志记录");
	}

	@Override
	public void doWork(){
		connect();
		subject.doWork();
		log();
	}
}
===================================================
12 责任链模式
/**
 * 举例：请假逐层审批
 * 概念：是一种处理请求的模式，它让多个处理器都有机会处理该请求，直到其中某个处理成功为止。责任链模式把多个处理器串成链，然后让请求在链上传递。属于行为型模式
 * 优点：请求和处理分开，请求者不需要知道处理者是谁，处理者也不需要知道请求的全貌，提供了系统的灵活性，缺点是降低了系统性能，比如可以直接找boss处理的
 * 的请求还需要把整个链条走一遍，不利于调试，类似于递归的方式，定位谁在处理它比较麻烦。
*/
public class ChainRespPattern{
	public static void main(String[] args) {
		Handler level1 = new Leader();
		Handler level2 = new Boss();
		level1.nextHandler(level2);

		level1.process(10);
		level1.process(11);
	}
}

abstract class Handler {

	protected Handler nextHandler;
	public void setNextHandler(Handler nextHandler) {
		this.nextHandler = nextHandler;
	}

	public abstract void process(Integer info);
}

class Leader extends Handler{
	@Override
	public void process(Integer info) {
		if (info > 0 && info < 11) {
			System.Out.println("Leader 处理！");
		} else {
			nextHandler.process(info);
		}
	}
}

class Boss extends Handler{
	@Override
	public void process(Integer info) {
		System.Out.println("Boss 处理！");
	}
}
===================================================
13 模板方法模式
/**
 * 定义一个操作中的算法的框架，而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
 * 
*/
public class TemplateMethodPattern{
	public static void main(String[] args) {
		Cooking cooking = new CookingFood();
		cooking.cook();
	}
}

abstract class Cooking{
	protected abstract void step1();
	protected abstract void step2();
	public void cook() {
		System.Out.println("做饭开始");
		step1();
		step2();
		System.Out.println("做饭结束");
	}
}

class CookingFood extends Cooking{
	@Override
	protected void step1() {
		System.Out.println("放鸡蛋和西红柿");
	}
	@Override
	protected void step2() {
		System.Out.println("少放盐多放味精");
	}
}
===================================================
14 享元模式
/**
 * 运用共享技术有效地支持大量细粒度的对象。池技术
*/

abstract class BikeFlyWeight{
	// 内部状态
	protected Integer state = 0; // 0是未使用中，1是使用中

	// userName外部状态
	abstract void ride(String userName);
	abstract void back();

	public Integer getState() {
		return state;
	}
}

class MoBikeFlyWeight extends BikeFlyWeight{
	// 定义新的内部状态，车架号
	private String bikeId;
	public MoBikeFlyWeight(String bikeId) {
		this.bikeId = bikeId;
	}

	@Override
	void ride(String userName) {
		state = 1;
		System.Out.println(userName + "骑" + bikeId + "号 自行车出行！");
	}

	@Override
	void back() {
		state = 0;
	}
}

// 享元工厂
class BikeFlyWeightFactory {
  private static BikeFlyWeightFactory instance = new BikeFlyWeightFactory();
  private Set<BikeFlyWeight> pool = new HashSet<>();

  public static BikeFlyWeightFactory getInstance(){
    return instance;
  }

  private BikeFlyWeightFactory(){
    for(int i = 0;i<2;i++){
       pool.add(new MoBikeFlyWeight ( bikeld: i+"号"));
    }

  public BikeFlyWeight getBike(){
    for(BikeFlyWeight bike : pool) {
      if(bike.getState() == 0)
        return bike;
    return null;
  }
}

public class FlyWeightPattern {
	public static void main(String[] args) {
		BikeFlyWeight bike1 = BikeFlyWeightFactory.getInstance().getBike();
		bike1.ride( userName: "ZhangSan") ;
		bike1.back();

		BikeFlyWeight bike2 = BikeFlyWeightFactory.getInstance().getBike();
		bike2. ride( userName: "Zhaosi");
		//bike2.back();

		BikeFlyWeight bike3 = BikeFlyWeightFactory.getInstance().getBike();
		bike3.ride( userName: "Wangwu") ;
		bike3.back();

		System.out.println(bike1 == bike2);
		System.out.println(bike2 == bike3);
	}
}
===================================================
15 命令模式
/**
 * 命令模式是一种行为设计模式，它可将请求转换为一个包含与请求相关的所有信息的独立对象。该转换让你能根据不同的请求将方法参数化，延迟请求执行或将其放入
 * 队列中，且能执行可撤销操作
 * 
 * 优点：前后端解耦，缺点：代码复杂
*/

/**
 * [GUI层]保存按钮
*/
class SaveButton{
	private Command command;
	/*
	...此处省略一堆渲染的逻辑
	*/
	public void bindCommand(Command command) {
		this.command = command;
	}
	public void doPrint(){
		if (command == null) {
			throw new RuntimeException("设备初始化失败！");
		}
		command.excute();
	}
}

/**
 * [业务逻辑层]打印服务
*/
class PrintService{
	public void print(String text) {
		System.Out.println(text);
	}
}

/**
 * 命令
*/
interface Command{
	void execute();
}

/**
 * 具体命令
*/
class PrintCommand implements Command{
	private PrintService serviceProvider = new PrintService();
	private TextBox box;

	public PrintCommand(TextBox box) {
		this.box = box;
	}

	@Override
	public void execute() {
		serviceProvider.print(box.getContext());
	}
}

/**
 * 文本编辑器的文本框
*/
class TextBox {
	private String context;

	public String getContext(){
		return context;
	}

	public void setContext(String context) {
		this.context = context;
	}
}
===================================================
16 生成器模式
import lombok.Builder;
import lombok.Data;

public class BuilderPattern {
	public static void main(String[] args) {
		House house = new House.HouseBuilder().wall(new Wall()).window(new Window()).door(new Door()).build():
	}
}

/**
 * 简单的房子
*/
@Data
@Builder
Class House{
	private Window window;
	private Door door;
	private Wall wall;
}
===================================================
17 原型模式
/**
 * 原型接口
*/
interface Prototype{
	Object clone();
}

/**
 * 飞机类
*/
class Plane implements Prototype{
	private String name;
	private String type;

	public Plane(){
		name = "Name:" + Math.random();
		type = "Type" + Math.randowm();
	}

	public Plane(Plane plane){
		this.name = plane.name;
		this.type = plane.type;
	}

	public String getName() {
		return name;
	}

	public String getType() {
		return type;
	}

	@Override
	public Object clone() {
		return new Plane(this);
	}
}

public class PrototypePattern{
	public static void main(String[] args) throws CloneNotSupportedException{
		Plane plane = new Plane();
		System.Out.println(plane.getName() + "  " + plane.getName());
		Plane clone = (Plane)plane.clone();
		System.Out.println(plane.getName() + "  " + plane.getName());
	}
}
===================================================
18 备忘录模式
/**
 * 是一种行为设计模式，允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态
*/

/**
 * [文档类]这里模拟编辑器
*/
class Document{
	private String content; // 需要备份的数据

	public BackUp save() {
		return new BackUp(content);
	}

	public void resume(BackUp backUp) { //resume 恢复
		content = backUp.content;
	}

	public void change(String content) {
		this.content = content;
	}

	public void print() {
		System.Out.println(content);
	}
}

/**
 * 【备忘录接口】
 * 定义元数据方法
*/
interface Memento{

}

/**
 * [备忘录类]
*/
class BackUp implements Memento{
	String content;
	public BackUp(String content) {
		this.content = content;
	}
}

/**
 * [备忘录栈]
*/
class History{
	Stack<BackUp> backUpStack = new Stack<>();
	public void add(BackUp backUp) {
		backUpStack.add(backUp);
	}
	public BackUp getLastVersion() {
		return backUpStack.pop();
	}
}

public class MementoPattern {
	public static void main(String[] args) {
		History history = new History();
		Document document = new Document();
		document.change(content: "abc");
		history.add(document.save());

		document.change(content: "def");
		history.add(document.save());

		document.change(content: "ghi");
		history.add(document.save());

		document.change(content: "Lmn");

		document.resume(history.getLastVersion());
		document.print();

		document.resume(history.getLastVersion());
		document.print();
	}
}
===================================================
19 迭代器模式
/**
 * ArrayList和LinkedList的Iterator方法
*/
===================================================
20 组合模式
/**
 * 小地区的人口统计-->全国人口普查
*/
===================================================
21 桥接模式
/**
 * 交叉连接的过程，维度层面上的解耦，比如支付渠道有微信支付，支付宝支付...,校验方面有密码、指纹、人脸，new WxPay(new PayFaceMode());
*/
===================================================
22 中介者模式
/**
 * 机场塔台控制飞机门的降落，服务的注册和发现
*/
===================================================
23 访问者模式

public class VisitorPattern{
	public static void main(String[] args) {
		EggRobot erDan = new EggRobot();
		erDan.calc();
		Visitor updatePack = new UpdateVisitor();
		erDan.accept(updatePack);
		erDan.calc();
	}
}



interface Visitor{
	void visitCPU(CPU cpu);
	void visitDisk(Hardware disk);
}

class UpdateVisitor implements Visitor{
	@Override
	public void visitCPU(CPU cpu) {
		cpu.command += ";1+1=2";
	}

	@Override
	public void visitDisk(Hardware disk) {
		disk.command += "记住：1+1=2";
	}
}

class EggRobbot{
	private Hardware disk;
	private CPU cpu;

	public EggRobot(){
		disk = new Hardware("记住 1+1=1")；
		cpu = new CPU("1+1=1");
	}

	public void calc() {
		disk.run();
		cpu.run();
	}

	public void accept(Visitor visitor){
		cpu.accept(visitor);
		disk.accept(Visitor);
	}
}

abstract class Hardware{
	String command;
	public Hardware(String command) {
		this.command = command;
	}

	public void run(){
		System.out.println(command);
	}

	public abstract void accept(Visitor visitor)
}

class CPU extends Hardware{
	String command;
  public CPU(String command) {
  	super(command)
  }

	@Override
	public void accept(visitor visitor) {
		visitor.visitCPU(this);
	}
}

class HardDisk extends Hardware {
	String command;
	public HardDisk(String command) {
		this.command = command;
	}

	@Override
	public void accept(Visitor visitor){
		visitor.visitDisk(this);
	}
}
===================================================
24 解释器模式


https://www.bilibili.com/video/BV1m741157EK/?spm_id_from=333.337.search-card.all.click&vd_source=407f609b5c86ff6ed2d0eef7f1353898
设计原则：
1. 单一职责原则：类的职责要单一，不能将太多的职责放在一个类中。4颗星
2. 开闭原则：软件实体对扩展是开发的，但对修改是关闭的，即在不修改一个软件实体的基础上去扩展其功能。5颗星
3. 里氏替换原则：在软件系统中，一个可以接受基类对象的地方必然可以接受一个子类对象。4颗星
4. 依赖倒转原则：要针对抽象层编程，而不要针对具体类编程。5颗星
5. 接口隔离原则：使用多个专门的接口来取代一个统一的接口。2颗星
6. 合成复用原则：在系统中应该尽量多使用组合和聚合关联关系，尽量少使用甚至不使用继承关系。4颗星
7. 迪米特法则：一个软件实体对其他实体的引用越少越好，或者说如果两个类不必彼此直接通信，那么这两个类就不应当反生直接的相互作用，而是通过引入一个第三者发生间接交互。3颗星